﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure;
using System.IO;
using System.Xml.Linq;

namespace ThreeByte.ActiveDeck.Web.Data
{
    public static class CloudStorageUtil
    {
        private static readonly string STORAGE_URI = @"https://activedeck.blob.core.windows.net"; 
        private static readonly StorageCredentials CREDENTIALS = new StorageCredentialsAccountAndKey("activedeck", "zOPKCq/cIaNQBxplzwoxg2xW47tVkiIksfgXME2uSFIkc0Whh9vQT38ghF9WRJ0IfSPIhUn9oCHOlmSqCwHcxA==");

        public static void StoreResource(string presentation, string name, byte[] data, string fileType = null) {

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);
            CloudBlobContainer blobContainer = new CloudBlobContainer("resources", client);
            blobContainer.CreateIfNotExist();

            string blobUri = string.Format("resources/{0}/{1}", presentation, name);
            CloudBlob b = new CloudBlob(blobUri, client);

            //TODO: Investigate BlobUploadOptions
            b.UploadByteArray(data);

            if(!(string.IsNullOrEmpty(fileType))) {
                b.Metadata["Type"] = fileType;
            }
            b.SetMetadata();

        }

        public static void StoreResourceBlock(string presentation, string name, byte[] data, string blockId, string contentHash) {

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);
            CloudBlobContainer blobContainer = new CloudBlobContainer("resources", client);
            blobContainer.CreateIfNotExist();

            string blobUri = string.Format("resources/{0}/{1}", presentation, name);
            CloudBlockBlob bb = new CloudBlockBlob(blobUri, client);
            bb.PutBlock(blockId, new MemoryStream(data), contentHash);
            //TODO: Investigate BlobUploadOptions
         
        }

        public static void CommitResourceBlock(string presentation, string name, List<string> blockIdList, string fileType = null) {

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);
            CloudBlobContainer blobContainer = new CloudBlobContainer("resources", client);
            blobContainer.CreateIfNotExist();

            string blobUri = string.Format("resources/{0}/{1}", presentation, name);
            CloudBlockBlob bb = new CloudBlockBlob(blobUri, client);
            bb.PutBlockList(blockIdList);
            //TODO: Investigate BlobUploadOptions
            if(!(string.IsNullOrEmpty(fileType))) {
                bb.Metadata["Type"] = fileType;
            }
            bb.SetMetadata();
        }

        public static void DeleteResource(string presentation, Guid id) {

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);
            CloudBlobContainer blobContainer = new CloudBlobContainer("resources", client);
            blobContainer.CreateIfNotExist();

            string blobUri = string.Format("resources/{0}/{1}", presentation, id);
            CloudBlockBlob bb = new CloudBlockBlob(blobUri, client);

            bool deleted = bb.DeleteIfExists();
        }

        public static XElement GetResourceList(string presentation, int count = 0, int skip = 0) {

            XNamespace ns = Service.ServiceConfiguration.NAMESPACE;
            XElement node = new XElement(ns + "Resources");

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);

            BlobRequestOptions options = new BlobRequestOptions();
            options.UseFlatBlobListing = true;
            string blobPrefix = string.Format("resources/{0}/", presentation);
            string absoluteBlobPrefix = string.Format("/resources/{0}/", presentation);

            ResultSegment<IListBlobItem> resultSegment = client.ListBlobsWithPrefixSegmented(blobPrefix, options);
            foreach(var blobItem in resultSegment.Results) {
                if(--skip >= 0) {
                    continue;    
                }
                node.Add(new XElement(ns + "Resource", new XAttribute("ID", blobItem.Uri.AbsolutePath.Replace(absoluteBlobPrefix, string.Empty))));
                if(--count == 0) {
                    return node;
                }
                
            }

            ResultContinuation continuation = resultSegment.ContinuationToken;

            while(continuation != null) {
                resultSegment = resultSegment.GetNext();
                foreach(var blobItem in resultSegment.Results) {
                    if(--skip >= 0) {
                        continue;
                    }
                    node.Add(new XElement(ns + "Resource", new XAttribute("ID", blobItem.Uri.AbsolutePath.Replace(absoluteBlobPrefix, string.Empty))));
                    if(--count == 0) {
                        return node;
                    }
                }
                continuation = resultSegment.ContinuationToken;
            }

            return node;
        }


        public static Stream GetResource(string presentation, string name, out string contentType) {

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);

            string blobUri = string.Format("resources/{0}/{1}", presentation, name);
            CloudBlob b = new CloudBlob(blobUri, client);
            
            MemoryStream mem = new MemoryStream();
            b.DownloadToStream(mem);
            mem.Seek(0, SeekOrigin.Begin);
            
            string fileType = b.Metadata["Type"];
            contentType = "application/octet-stream";//Default binary type
            if(!(string.IsNullOrEmpty(fileType))) {
                if(fileType == "PNG") {
                    contentType = "image/png";
                } else if(fileType == "JPEG") {
                    contentType = "image/jpeg";
                }
            }
            return mem;
        }

        public static XElement GetResourceInfo(string presentation, string name) {
            XNamespace ns = Service.ServiceConfiguration.NAMESPACE;
            XElement node = new XElement(ns+ "Resource");

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);

            //Try to get as a page blob
            CloudBlob blobReference;
            try {
                blobReference = client.GetPageBlobReference(string.Format("resources/{0}/{1}", presentation, name));
                blobReference.FetchAttributes();
            } catch {
                //If that fails, try to get as a blockBlob
                //Has to be one or the other
                try {
                    blobReference = client.GetBlockBlobReference(string.Format("resources/{0}/{1}", presentation, name));
                    blobReference.FetchAttributes();
                } catch {
                    //Otherwise it doesn't exist
                    return new XElement(ns + "ResourceNotFound");
                }
            }

            //Get Size
            int size = (int)(blobReference.Attributes.Properties.Length);

            //Get Last Modified
            DateTime lastModified = blobReference.Attributes.Properties.LastModifiedUtc;

            //Get Type
            string fileType = blobReference.Metadata["Type"];

            node.Add(new XAttribute("ID", name));
            node.Add(new XAttribute("Size", size));
            node.Add(new XAttribute("Type", (fileType ?? string.Empty)));
            node.Add(new XAttribute("LastModified", lastModified));
            
            return node;
        }

        //Storing/Retrieving Infrastructure download files
        public static void StoreDownload(string container, string name, byte[] data, string fileType = null) {

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);
            CloudBlobContainer blobContainer = new CloudBlobContainer(@"downloads", client);
            blobContainer.CreateIfNotExist();

            string blobUri = string.Format("downloads/{0}/{1}", container, name);
            CloudBlob b = new CloudBlob(blobUri, client);

            b.UploadByteArray(data);

            if(!(string.IsNullOrEmpty(fileType))) {
                b.Metadata["Type"] = fileType;
            }
            b.SetMetadata();
        }

        //Storing/Retrieving Infrastructure download files
        public static void CopyDownload(string sourceName, string destName) {

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);
            CloudBlobContainer blobContainer = new CloudBlobContainer(@"downloads", client);
            blobContainer.CreateIfNotExist();

            string sourceUri = string.Format("downloads/{0}", sourceName);
            CloudBlob sourceBlob = new CloudBlob(sourceUri, client);

            string destUri = string.Format("downloads/{0}", destName);
            CloudBlob destBlob = new CloudBlob(destUri, client);

            destBlob.CopyFromBlob(sourceBlob);
        }

        public static Stream GetDownload(string container, string name) {

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);

            string blobUri = string.Format("downloads/{0}/{1}", container, name);
            CloudBlob b = new CloudBlob(blobUri, client);

            MemoryStream mem = new MemoryStream();
            b.DownloadToStream(mem);
            mem.Seek(0, SeekOrigin.Begin);

            //fileType = b.Metadata["Type"];
            return mem;
        }

        public static void StoreErrorReport(string id, string source, string version, string reportData) {

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);
            CloudBlobContainer blobContainer = new CloudBlobContainer("error-reports", client);
            blobContainer.CreateIfNotExist();

            string blobUri = string.Format("error-reports/{0}", id);
            CloudBlob b = new CloudBlob(blobUri, client);

            //TODO: Investigate BlobUploadOptions
            b.UploadByteArray(Encoding.Default.GetBytes(reportData));

            if(!(string.IsNullOrEmpty(source))) {
                b.Metadata["Source"] = source;
            }
            if(!(string.IsNullOrEmpty(version))) {
                b.Metadata["Version"] = version;
            }
            b.SetMetadata();

        }

        public static Stream GetErrorReport(string id) {

            CloudBlobClient client = new CloudBlobClient(STORAGE_URI, CREDENTIALS);

            string blobUri = string.Format("error-reports/{0}", id);
            CloudBlob b = new CloudBlob(blobUri, client);

            MemoryStream mem = new MemoryStream();
            b.DownloadToStream(mem);
            mem.Seek(0, SeekOrigin.Begin);

            return mem;
        }
    }
}
